package com.ruoyi.system.util;

import cn.hutool.core.io.FileUtil;
import com.ruoyi.system.domain.vo.PointCoordinate;
import it.geosolutions.geoserver.rest.GeoServerRESTManager;
import it.geosolutions.geoserver.rest.GeoServerRESTPublisher;
import it.geosolutions.geoserver.rest.GeoServerRESTReader;
import it.geosolutions.geoserver.rest.decoder.RESTCoverage;
import it.geosolutions.geoserver.rest.decoder.RESTDataStore;
import it.geosolutions.geoserver.rest.decoder.RESTDataStoreList;
import it.geosolutions.geoserver.rest.decoder.RESTLayer;
import it.geosolutions.geoserver.rest.encoder.GSLayerEncoder;
import it.geosolutions.geoserver.rest.encoder.datastore.GSPostGISDatastoreEncoder;
import it.geosolutions.geoserver.rest.encoder.feature.GSFeatureTypeEncoder;
import org.geotools.data.DataStore;
import org.geotools.data.DataStoreFinder;
import org.geotools.data.FeatureSource;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.shapefile.ShapefileDataStoreFactory;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.Point;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.zip.ZipException;

public class GeoServerUtils {



    //geoserver服务地址
    private static String GEOSERVER_URL = "http://localhost:9700/geoserver";
    //geoserver登录用户
    private static String GEOSERVER_USER = "admin";
    //geoserver登录密码
    private static String GEOSERVER_PWD = "geoserver";

    //发布postgis中的数据
    public static boolean GeoserverPublishPostGISData(String ws, String store_name, String table_name, String epsg) {

        try {
            //postgis连接配置
            String postgisHost = "localhost";
            int postgisPort = 5432;
            String postgisUser ="postgres";
            String postgisPassword = "123456";
            String postgisDatabase = "test";
            String postgisSchema = "public";

            URL u = new URL(GEOSERVER_URL);
            System.err.println(GEOSERVER_URL);
            GeoServerRESTManager manager = new GeoServerRESTManager(u, GEOSERVER_USER, GEOSERVER_PWD);

            GeoServerRESTPublisher publisher = manager.getPublisher();
            List<String> workspaces = manager.getReader().getWorkspaceNames();
            if (!workspaces.contains(ws)) {
                boolean createws = publisher.createWorkspace(ws);
                System.out.println("create ws : " + createws);
            } else {
                System.out.println("workspace已经存在了,ws :" + ws);
            }

            //判断数据存储（datastore）是否已经存在，不存在则创建
            RESTDataStore restStore = manager.getReader().getDatastore(ws, store_name);
            if (restStore == null) {
                GSPostGISDatastoreEncoder store = new GSPostGISDatastoreEncoder(store_name);
                store.setHost(postgisHost);
                store.setPort(postgisPort);
                store.setUser(postgisUser);
                store.setPassword(postgisPassword);
                store.setDatabase(postgisDatabase);
                store.setSchema(postgisSchema);
                store.setConnectionTimeout(20);
                /*store.setName(schema);*/
                store.setMaxConnections(20);
                store.setMinConnections(1);
                store.setExposePrimaryKeys(true);
                boolean createStore = manager.getStoreManager().create(ws, store);
                System.out.println("create store : " + createStore);
            } else {
                System.out.println("数据存储已经存在了,store:" + store_name);
            }

            //判断图层是否已经存在，不存在则创建并发布
            RESTLayer layer = manager.getReader().getLayer(ws, table_name);
            if (layer == null) {
                GSFeatureTypeEncoder pds = new GSFeatureTypeEncoder();
                pds.setTitle(table_name);
                pds.setName(table_name);
                pds.setSRS("EPSG:"+epsg);
                GSLayerEncoder layerEncoder = new GSLayerEncoder();
                //layerEncoder 可以对shp文件添加样式
                boolean publish = manager.getPublisher().publishDBLayer(ws, store_name, pds, layerEncoder);
                System.out.println("publish : " + publish);
                return publish;
            } else {
                System.out.println("表已经发布过了,table:" + table_name);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    //发布tiff

    /**
     *
     * @param workspace 工作区
     * @param storeName
     * @param coverageName  图层区
     * @param tiffFile  文件路径
     * @return
     */
    public static boolean GeoserverPublishTiffData(String workspace, String storeName, String coverageName, String tiffFile) {
        try {
            GeoServerRESTPublisher geoServerRESTPublisher = new GeoServerRESTPublisher(GEOSERVER_URL,GEOSERVER_USER,GEOSERVER_PWD);
            GeoServerRESTReader geoServerRESTReader = new GeoServerRESTReader(GEOSERVER_URL,GEOSERVER_USER,GEOSERVER_PWD);

            File geotiff = new File(tiffFile);

            //workspace是否存在，不存在则新建。
            List<String> workspacesList = geoServerRESTReader.getWorkspaceNames();
            boolean wsNull = !workspacesList.contains(workspace);
            if(wsNull){
                geoServerRESTPublisher.createWorkspace(workspace);
            }

            //store是否存在，不存在则新建并发布数据。
            RESTDataStoreList datastoresList = geoServerRESTReader.getDatastores(workspace);
            List<String> datastoreNameList = datastoresList.getNames();
            boolean storeNull = !datastoreNameList.contains(storeName);

            boolean publishSuccess = false;


            if(storeNull){
                publishSuccess  = geoServerRESTPublisher.publishGeoTIFF(workspace,storeName,coverageName,geotiff);
                System.out.println("数据发布是否成功："+publishSuccess);

                return publishSuccess;
            } else{
                publishSuccess = true; // 已存在视为“发布成功”状态
                System.out.println("数据已经发布过了，不能重复发布！");
            }


        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return false;
    }


    /**
     * 获取GeoTIFF图层的中心点坐标
     * @param workspace 工作区
     * @param coverageName 覆盖范围名（图层名）
     * @return 中心点坐标 [x, y]，若失败返回null
     */
    public static double[] GeoserverPublishTiffDataReturnZx(String workspace, String storeName, String coverageName, String tiffFile) {
        try {
            GeoServerRESTPublisher geoServerRESTPublisher = new GeoServerRESTPublisher(GEOSERVER_URL,GEOSERVER_USER,GEOSERVER_PWD);
            GeoServerRESTReader geoServerRESTReader = new GeoServerRESTReader(GEOSERVER_URL,GEOSERVER_USER,GEOSERVER_PWD);

            File geotiff = new File(tiffFile);

            //workspace是否存在，不存在则新建。
            List<String> workspacesList = geoServerRESTReader.getWorkspaceNames();
            boolean wsNull = !workspacesList.contains(workspace);
            if(wsNull){
                geoServerRESTPublisher.createWorkspace(workspace);
            }

            //store是否存在，不存在则新建并发布数据。
            RESTDataStoreList datastoresList = geoServerRESTReader.getDatastores(workspace);
            List<String> datastoreNameList = datastoresList.getNames();
            boolean storeNull = !datastoreNameList.contains(storeName);

            boolean publishSuccess = false;


            if(storeNull){
                publishSuccess  = geoServerRESTPublisher.publishGeoTIFF(workspace,storeName,coverageName,geotiff);
                System.out.println("数据发布是否成功："+publishSuccess);

            } else{
                publishSuccess = true; // 已存在视为“发布成功”状态
                System.out.println("数据已经发布过了，不能重复发布！");
            }

            // 3. 发布成功后，获取中心点
            if (publishSuccess) {
                return calculateCenter(geoServerRESTReader, workspace, storeName, coverageName);
            }
        } catch (Exception e) {
            e.printStackTrace();

        }
        return null;
    }

    /**
     * 计算GeoTIFF中心点（核心逻辑：直接从RESTCoverage获取边界）
     */
    private static double[] calculateCenter(GeoServerRESTReader reader,
                                            String workspace, String storeName, String coverageName) {
        try {
            // 获取覆盖范围元数据
            RESTCoverage coverage = reader.getCoverage(workspace, storeName, coverageName);
            if (coverage == null) {
                System.out.println("未找到图层元数据");
                return null;
            }

            // 获取边界值（低版本直接通过RESTCoverage的方法获取）
            double minX = getBoundaryValue(coverage, "getMinX");
            double maxX = getBoundaryValue(coverage, "getMaxX");
            double minY = getBoundaryValue(coverage, "getMinY");
            double maxY = getBoundaryValue(coverage, "getMaxY");

            // 若原生边界为空，尝试经纬度边界
            if (minX == Double.MIN_VALUE) {
                minX = getBoundaryValue(coverage, "getLatLonMinX");
                maxX = getBoundaryValue(coverage, "getLatLonMaxX");
                minY = getBoundaryValue(coverage, "getLatLonMinY");
                maxY = getBoundaryValue(coverage, "getLatLonMaxY");
            }

            // 计算中心点
            if (minX != Double.MIN_VALUE && maxX != Double.MIN_VALUE
                    && minY != Double.MIN_VALUE && maxY != Double.MIN_VALUE) {
                return new double[]{(minX + maxX) / 2, (minY + maxY) / 2};
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 通用方法：调用RESTCoverage的边界值getter方法
     */
    private static double getBoundaryValue(RESTCoverage coverage, String methodName) {
        try {
            // 调用方法（如getMinX()、getLatLonMinX()）
            return (Double) coverage.getClass().getMethod(methodName).invoke(coverage);
        } catch (Exception e) {
            // 方法不存在时返回默认值
            return Double.MIN_VALUE;
        }
    }

    //发布shp文件
    public static boolean GeoserverPublishShpFile(String workspace, String storeName, String coverageName, String shpFile) {
        try {
            //storeName 需要与压缩包名称一致，  coverageName 需要与.shp文件名称一致
            GeoServerRESTPublisher geoServerRESTPublisher = new GeoServerRESTPublisher(GEOSERVER_URL,GEOSERVER_USER,GEOSERVER_PWD);
            GeoServerRESTReader geoServerRESTReader = new GeoServerRESTReader(GEOSERVER_URL,GEOSERVER_USER,GEOSERVER_PWD);

            File shpfile = new File(shpFile);

            //workspace是否存在，不存在则新建。
            List<String> workspacesList = geoServerRESTReader.getWorkspaceNames();
            boolean wsNull = !workspacesList.contains(workspace);
            if(wsNull){
                geoServerRESTPublisher.createWorkspace(workspace);
            }

            //store是否存在，不存在则新建并发布数据。
            RESTDataStoreList datastoresList = geoServerRESTReader.getDatastores(workspace);

            List<String> datastoreNameList = datastoresList.getNames();

            boolean storeNull = !datastoreNameList.contains(storeName);

            if(storeNull){
                boolean result = geoServerRESTPublisher.publishShp(workspace,storeName,coverageName,shpfile);

                System.out.println("数据发布是否成功："+result);
                return result;
            } else{
                System.out.println("数据已经发布过了，不能重复发布！");
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    //上传文件路径解析shp数据

    /**
     *
     * @param filePath  shp文件路径
     * @param temp  临时路径
     * @param zipPassword  压缩包密码
     * @return
     */
    public static Map<String,String> jiexiShp(String filePath,String temp,String zipPassword) {

       Map<String, String> stringStringHashMap = new HashMap<>();



        File tempZip = new File(filePath);

        int i = tempZip.getName().lastIndexOf(".");
        String substring = tempZip.getName().substring(0, i);
        stringStringHashMap.put("zipName",substring);


        File pathFile = null;
        try {
            //创建临时文件目录
            String f = temp;
            File file1 = new File(f);
            if (!file1.exists()) {
                file1.mkdirs();
            }
            //临时保存上传的zip文件
            String originalFilename = tempZip.getName();

            //解压后的路径
            String path = f+ originalFilename.substring(0, originalFilename.lastIndexOf("."));

            pathFile = new File(path);

            ZipByPassUtils.unzip(tempZip, path, zipPassword);
            //拿到路径
            List<File> loopFiles = FileUtil.loopFiles(path);
            //判断文件后缀
            for (File loopFile : loopFiles) {
                if (loopFile.getName().endsWith(".shp")){

                    int iir = loopFile.getName().lastIndexOf(".");
                    String shpName = loopFile.getName().substring(0, iir);
                    stringStringHashMap.put("shpName",shpName);

//                    List<PointCoordinate> hqdw = hqdw(loopFile);
//                    hqdw.forEach(item->{
//                        stringStringHashMap.put("jd",String.valueOf(item.getX()));
//                        stringStringHashMap.put("wd",String.valueOf(item.getY()));
//                    });

                    Map<String, String> xyMap = WdcShpUtil.shipZb(loopFile);

                    if (xyMap!=null){
                        stringStringHashMap.put("jd",xyMap.get("x"));
                        stringStringHashMap.put("wd",xyMap.get("y"));
                    }


                }

            }
        } catch (ZipException | net.lingala.zip4j.exception.ZipException e) {
            e.printStackTrace();
        } finally {

            if (pathFile != null) {
                FileUtil.del(pathFile);
            }
        }

        return stringStringHashMap;
    }

    private static List<PointCoordinate> hqdw(File loopFile) {
        DataStore dataStore = null;
        FeatureIterator<SimpleFeature> iterator = null;
        List<PointCoordinate> pointList = new ArrayList<>();
        try {
            // 1. 配置SHP数据存储参数（解决中文乱码）
            Map<String, Object> params = new HashMap<>();
            params.put(ShapefileDataStoreFactory.URLP.key, loopFile.toURI().toURL());
//            params.put(ShapefileDataStoreFactory.ENCODING.key, "GBK"); // 属性表编码（根据实际调整：GBK/UTF-8）

            // 2. 加载SHP数据存储
            dataStore = DataStoreFinder.getDataStore(params);
            if (dataStore == null) {
                System.err.println("错误：无法加载SHP文件，请检查文件完整性");
                return null;
            }

            // 关键修改：通过ShapefileDataStore的setCharset方法设置编码
            if (dataStore instanceof ShapefileDataStore) {
                // 根据实际编码调整（GBK或UTF-8）
                ((ShapefileDataStore) dataStore).setCharset(Charset.forName("GBK"));
            }


            // 3. 获取要素源（图层数据）
            String typeName = dataStore.getTypeNames()[0]; // 获取第一个图层名
            FeatureSource<SimpleFeatureType, SimpleFeature> featureSource = dataStore.getFeatureSource(typeName);

            // 4. 遍历所有要素，提取几何坐标
            FeatureCollection<SimpleFeatureType, SimpleFeature> features = featureSource.getFeatures();
            iterator = features.features();

            while (iterator.hasNext()) {
                SimpleFeature feature = iterator.next();
                Geometry geometry = (Geometry) feature.getDefaultGeometry(); // 获取几何对象

                if (geometry == null) {
                    System.out.println("警告：跳过无几何信息的要素");
                    continue;
                }

                // 根据几何类型提取坐标点
                extractCoordinatesByGeometryType(geometry, pointList);
            }

            System.out.println("点位提取完成，共提取 " + pointList.size() + " 个点位");
            return pointList;

        } catch (Exception e) {
            System.err.println("提取点位失败：" + e.getMessage());
            e.printStackTrace();
            return null;
        } finally {
            // 释放资源
            if (iterator != null) {
                iterator.close();
            }
            if (dataStore != null) {
                dataStore.dispose();
            }
        }
    }

    /**
     * 根据几何类型提取坐标点
     * @param geometry 几何对象（Point/LineString/Polygon等）
     * @param pointList 存储提取的点位列表
     */
    private static void extractCoordinatesByGeometryType(Geometry geometry, List<PointCoordinate> pointList) {
        String geoType = geometry.getGeometryType();

        switch (geoType) {
            case "Point":
                // 点要素：直接获取坐标
                Point point = (Point) geometry;
                pointList.add(new PointCoordinate(geoType, point.getX(), point.getY()));
                break;

//            case "LineString":
//                // 线要素：提取所有顶点
//                LineString line = (LineString) geometry;
//                addCoordinatesToPointList(line.getCoordinates(), geoType, pointList);
//                break;
//
//            case "Polygon":
//                // 面要素：提取外环所有顶点（忽略内环）
//                Polygon polygon = (Polygon) geometry;
//                LinearRing outerRing = polygon.getExteriorRing();
//                addCoordinatesToPointList(outerRing.getCoordinates(), geoType, pointList);
//                break;
//
//            case "MultiPoint":
//                // 多点要素：提取每个点的坐标
//                MultiPoint multiPoint = (MultiPoint) geometry;
//                for (int i = 0; i < multiPoint.getNumGeometries(); i++) {
//                    Point p = (Point) multiPoint.getGeometryN(i);
//                    pointList.add(new PointCoordinate(geoType, p.getX(), p.getY()));
//                }
//                break;
//
//            case "MultiLineString":
//                // 多线要素：提取每条线的所有顶点
//                MultiLineString multiLine = (MultiLineString) geometry;
//                for (int i = 0; i < multiLine.getNumGeometries(); i++) {
//                    LineString lin2e = (LineString) multiLine.getGeometryN(i);
//                    addCoordinatesToPointList(lin2e.getCoordinates(), geoType, pointList);
//                }
//                break;
//
//            case "MultiPolygon":
//                // 多面要素：提取每个面的外环顶点
//                MultiPolygon multiPolygon = (MultiPolygon) geometry;
//                for (int i = 0; i < multiPolygon.getNumGeometries(); i++) {
//                    Polygon polyg2n = (Polygon) multiPolygon.getGeometryN(i);
//                    LinearRing outerRing2 = polyg2n.getExteriorRing();
//                    addCoordinatesToPointList(outerRing2.getCoordinates(), geoType, pointList);
//                }
//                break;

            default:
                System.out.println("警告：不支持的几何类型：" + geoType);
        }
    }
    /**
     * 将坐标数组添加到点位列表
     * @param coordinates 坐标数组
     * @param geometryType 几何类型
     * @param pointList 目标点位列表
     */
    private static void addCoordinatesToPointList(Coordinate[] coordinates, String geometryType, List<PointCoordinate> pointList) {
        for (Coordinate coord : coordinates) {
            // 过滤无效坐标（排除NaN值）
            if (!Double.isNaN(coord.x) && !Double.isNaN(coord.y)) {
                pointList.add(new PointCoordinate(geometryType, coord.x, coord.y));
            }
        }
    }
    //删除图层
    public static boolean deleteGeoserverLayerGroupData() {
        boolean test = false;
        try {
            URL u = new URL(GEOSERVER_URL);
            GeoServerRESTManager manager = new GeoServerRESTManager(u, GEOSERVER_USER, GEOSERVER_PWD);
            GeoServerRESTPublisher publisher = manager.getPublisher();
            test = publisher.removeLayer("ws_test","coverage_1");
        } catch (IOException e) {
        } catch (Exception e) {
        }
        return test;
    }

    //删除图层
    public static boolean deleteGeoserverLayerGroupData(String workspace,String layerName) {
        boolean test = false;
        try {
            URL u = new URL(GEOSERVER_URL);
            GeoServerRESTManager manager = new GeoServerRESTManager(u, GEOSERVER_USER, GEOSERVER_PWD);
            GeoServerRESTPublisher publisher = manager.getPublisher();
            test = publisher.removeLayer(workspace,layerName);



        } catch (IOException e) {
        } catch (Exception e) {
        }
        return test;
    }

    //删除shp图层
    public static boolean deleteShpGeoserverLayerGroupData(String workspace,String storeName,String layerName) {
        boolean test = false;
        try {
            URL u = new URL(GEOSERVER_URL);
            GeoServerRESTManager manager = new GeoServerRESTManager(u, GEOSERVER_USER, GEOSERVER_PWD);
            GeoServerRESTPublisher publisher = manager.getPublisher();
            //删除图层
             publisher.removeLayer(workspace,layerName);

            try {
                publisher.unpublishFeatureType(workspace, storeName, layerName);
            } catch (Exception e) {
            }

            try {
                publisher.removeDatastore(workspace, storeName, true); // true表示强制删除
            } catch (Exception e) {
                // 数据存储可能不存在，忽略错误
            }

        } catch (IOException e) {
        } catch (Exception e) {
        }
        return test;
    }

    public static void main(String[] args) throws Exception {
//        GeoserverPublishPostGISData("ws_test" , "store_test_shp", "shp_data_1654008664545","4326");
//        GeoserverPublishShpFile("ws_test", "sheng","shengout","F:\\workspaces\\testshp\\src\\main\\resources\\sheng.zip");
        GeoserverPublishTiffData("wdc_ws", "store_wdc_tiff","coverage_1","C:\\Users\\不能上火\\OneDrive\\桌面\\图层\\MianYang.tif");

        deleteGeoserverLayerGroupData();

    }

    public static int isShp(String filePath, String temp, String zipPassword) {



        File tempZip = new File(filePath);

        File pathFile = null;
        try {
            //创建临时文件目录
            String f = temp;
            File file1 = new File(f);
            if (!file1.exists()) {
                file1.mkdirs();
            }
            //临时保存上传的zip文件
            String originalFilename = tempZip.getName();

            //解压后的路径
            String path = f+ originalFilename.substring(0, originalFilename.lastIndexOf("."));

            pathFile = new File(path);

            ZipByPassUtils.unzip(tempZip, path, zipPassword);
            //拿到路径
            List<File> loopFiles = FileUtil.loopFiles(path);
            String collect = loopFiles.stream().map(File::getName).collect(Collectors.joining(","));


            if (
            collect.contains(".cpg") && collect.contains(".dbf")&&
            collect.contains(".prj")&&
            collect.contains(".qmd") &&
            collect.contains(".shp") &&
            collect.contains(".shx")
        ){


                return 1;
            }


        } catch (ZipException | net.lingala.zip4j.exception.ZipException e) {
            e.printStackTrace();
        } finally {
            if (pathFile != null) {
                FileUtil.del(pathFile);
            }
        }

        return 0;
    }
}
